package track

import (
	"log"
	"time"

	"gitee.com/general252/gortc/pkg/format"
	"gitee.com/general252/gortc/pkg/rtcsdp"
	"gitee.com/general252/gortc/pkg/rtprtcp"
	"gitee.com/general252/gortc/pkg/streammuxer"
	"github.com/pion/rtcp"
	"github.com/pion/rtp"
)

type Sender struct {
	muxer  streammuxer.StreamMuxer
	writer RtpRtcpWriter
	media  *rtcsdp.Media
	format format.Format

	getFirstPacketNTP func() (time.Time, bool)

	timeEncoder *rtprtcp.RtpTimeEncoder
	rtcpSender  *rtprtcp.RTCPSender // 发送者报告
}

func NewSender(
	muxer streammuxer.StreamMuxer,
	writer RtpRtcpWriter,
	media *rtcsdp.Media,
	ct format.Format,
	getFirstPacketNTP func() (time.Time, bool),
) *Sender {

	var (
		clockRate = ct.ClockRate()
		period    = time.Second * 5
		timeNow   = time.Now
	)

	sender := rtprtcp.NewRTCPSender(clockRate, period, timeNow, func(packet rtcp.Packet) {
		_ = writer.WriteRTCP([]rtcp.Packet{packet}, nil)
	})

	c := &Sender{
		muxer:             muxer,
		writer:            writer,
		getFirstPacketNTP: getFirstPacketNTP,
		media:             media,
		format:            ct,
		timeEncoder:       rtprtcp.NewRtpTimeEncoder(clockRate, 0),
		rtcpSender:        sender,
	}

	c.sender()

	return c
}

func (c *Sender) Open() error {
	return nil
}

func (c *Sender) Close() {
	if c.rtcpSender != nil {
		c.rtcpSender.Close()
	}
}

func (c *Sender) sender() {

	streamId := streammuxer.NewStreamIdRTP(c.media.SSRC, c.format.PayloadType())

	// 接收本地要发送的包, 交给网络接口发送
	_, err := c.muxer.AddPull(streamId, streammuxer.PullInfo{
		Name: "对本地发送的包处理后发送",
		OnPacket: func(info *streammuxer.StreamInfo, data *streammuxer.StreamData) {
			// 收到数据包, 发送给远方
			switch value := data.Data.(type) {
			case *rtp.Packet:
				pkt := value
				_ = c.writePacketRTP(pkt, data.Ntp)
			}
		},
	})
	if err != nil {
		log.Println(err)
	}

	// 接收rtcp
	rtcpStreamId := streammuxer.NewStreamIdRTCP(c.media.SSRC)
	_, err = c.muxer.AddPull(rtcpStreamId, streammuxer.PullInfo{
		Name: "",
		OnPacket: func(info *streammuxer.StreamInfo, data *streammuxer.StreamData) {
			switch value := data.Data.(type) {
			case *rtcp.ReceiverReport:
				pkt := value
				c.readPacketRTCP(pkt)
			}
		},
	})
	if err != nil {
		log.Println(err)
	}
}

func (c *Sender) readPacketRTCP(rr *rtcp.ReceiverReport) {
	log.Printf("接收者报告: %s", rr.String())
}

func (c *Sender) writePacketRTP(pkt *rtp.Packet, ntp time.Time) error {
	if startTime, ok := c.getFirstPacketNTP(); ok {
		ts := ntp.Sub(startTime)
		pkt.Timestamp = c.timeEncoder.Encode(ts)
	}

	c.rtcpSender.ProcessPacket(pkt, ntp, c.format.PTSEqualsDTS(pkt))

	return c.writer.WriteRTP(pkt, nil)
}
